﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel;
using System.ServiceModel.Web;
using FlightSearchServer;
using System.Net;
using System.Text.RegularExpressions;

namespace Client
{
    class ClientApplication
    {
        IFlightSearchServiceClients channel = null;
        WebChannelFactory<IFlightSearchServiceClients> channelFactory = null;

        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("Please provide flight search service url as parameter");
                return;
            }

            string serviceUrl = args[0];
            ClientApplication client = new ClientApplication();

            client.StartApplication(serviceUrl);
            //app is running <=here=> :-)
            client.CloseApplication();
        }

        void StartApplication(string serviceUrl)
        {
            try
            {
                channelFactory = new WebChannelFactory<IFlightSearchServiceClients>(new Uri(serviceUrl));
                channel = channelFactory.CreateChannel();
            }
            catch (Exception e)
            {
                Console.WriteLine("Can't create server connection, please check server url is ok");
                return;
            }

            Console.WriteLine("Ticket search: 'search <src> <dst> <date>'");
            Console.WriteLine("Ticket reservation: 'reserve <seller> <fNum> <date>'");
            Console.WriteLine("Reservation cancelling: 'cancel <seller> <reservation ID>'");

            while (true)
            {
                Console.Write("> ");
                string query = Console.ReadLine().Trim();
                
                //continue if blank line is entered
                if (string.IsNullOrEmpty(query))
                {
                    continue;
                }

                //split line by whitespaces
                string[] commands = Regex.Split(query, @"\s+");

                switch (commands[0])
                {
                    case "exit":
                        return;

                    case "search":
                        if (commands.Length != 4)
                        {
                            Console.WriteLine("Wrong query, try 'search <src> <dst> <date>'");
                            continue;
                        }
                        Search(commands);
                        break;

                    case "reserve":
                        if (commands.Length != 4)
                        {
                            Console.WriteLine("Wrong query, try 'reserve <seller> <fNum> <date>'");
                            continue;
                        }
                        Reserve(commands);
                        break;

                    case "cancel":
                        if (commands.Length != 3)
                        {
                            Console.WriteLine("Wrong query, try 'cancel <seller> <reservation ID>'");
                            continue;
                        }
                        Cancel(commands);
                        break;

                    default:
                        Console.WriteLine("Wrong query, try 'search', 'reserve' or 'cancel'");
                        break;
                }
            }
        }

        void CloseApplication()
        {
            channelFactory.Close();
        }

        void Search(string[] query)
        {
            TicketList tickets = null;
            try{
                //NOTE: parameters order isn't same as in command line
                // date, src, dst  instead of src, dst, date
                tickets = channel.SearchTickets(query[3], query[1], query[2]);
            }catch(Exception e){
                if (e.InnerException is WebException 
                    && ((WebException)e.InnerException).Status == WebExceptionStatus.ProtocolError)
                {
                    HttpWebResponse resp = (HttpWebResponse)((WebException)e.InnerException).Response;
                    Console.WriteLine(resp.StatusDescription + " " + resp.StatusCode);
                    Console.WriteLine("Connection problem, protocol error");
                    return;
                }
                else
                {
                    Console.WriteLine("Connection problem");
                    return;
                }
            }

            if (tickets == null)
            {
                //something went bad with server connection
                Console.WriteLine("Connection problem");
                return;
            }

            if (tickets.Count == 0)
            {
                Console.WriteLine("No flights found");
                return;
            }
            else
            {
                Console.WriteLine("{0} flight{1} found:", tickets.Count, tickets.Count > 1 ? "s" : " ");
                foreach (Ticket ticket in tickets)
                {
                    Console.WriteLine("{0} {1} {2} seats ${3}", ticket.Company, ticket.Flight, ticket.Seats, ticket.Price);
                }
            }
        }

        void Reserve(string[] query)
        {
            string reservationId;

            try
            {
                //escaping parameters sent in uri to prevent making request with wrong uri 
                // wcf doesn't support urlencoded strings as parameters, so we just preventing
                // sending slashes in parameters
                string query1safe = query[1].Replace("/", "-");
                query1safe = query1safe.Replace("\\", "-");
                query1safe = query1safe.Replace("#", "-");

                reservationId = channel.CreateReservation(query1safe,  query[2], query[3]);
            }
            catch(Exception e)
            {
                if (e.InnerException is WebException 
                    && ((WebException)e.InnerException).Status == WebExceptionStatus.ProtocolError)
                {
                    HttpWebResponse resp = (HttpWebResponse)((WebException)e.InnerException).Response;
                    Console.WriteLine(resp.StatusDescription);
                    return;
                }
                else
                {
                    Console.WriteLine("Connection problem");
                    return;
                }
            }

            if (reservationId == null)
            {
                //something went bad with server connection
                Console.WriteLine("Connection problem");
                return;
            }

            Console.WriteLine("OK, reservation ID: {0}", reservationId);
        }

        void Cancel(string[] query)
        {
            try
            {
                //escaping parameters sent in uri to prevent making request with wrong uri 
                // wcf doesn't support urlencoded strings as parameters, so we just preventing
                // sending slashes in parameters
                string query1safe = query[1].Replace("/", "-");
                query1safe = query1safe.Replace("\\", "-");
                query1safe = query1safe.Replace("#", "-");

                string query2safe = query[2].Replace("/", "-");
                query2safe = query2safe.Replace("\\", "-");
                query2safe = query2safe.Replace("#", "-");

                channel.CancelReservation(query1safe, query2safe);
            }
            catch (Exception e)
            {
                if (e.InnerException is WebException 
                    && ((WebException)e.InnerException).Status == WebExceptionStatus.ProtocolError)
                {
                    HttpWebResponse resp = (HttpWebResponse)((WebException)e.InnerException).Response;
                    Console.WriteLine(resp.StatusDescription);
                    return;
                }
                else
                {
                    Console.WriteLine("Connection problem");
                    return;
                }
            }
            Console.WriteLine("OK");
        }
    }
}
